一、介绍
本章的删除与前两节的数据添加(Put)和数据查询(Get)的使用方法基本上是相同的,只不过要介绍一下在进行删除过程中一些需要注意的地方。
二、过程介绍
Delete删除的过程分为单行删除、多行删除与原子性操作
1、单行删除
HBase的删除并不像传统关系型数据库的删除,HBase删除动作并不会立刻将HBase存储的数据进行删除,而是心在制定的KeyValue存储单元上打上删除标志。等到下一次region合并、分裂等操作时才会将所有的数据进行移除。
public void delete(String tableName,String rowKey,String family,String qualifier,String timeStampe,String value)
{
Configuration conf=init\(\);
try {
//判断是表是否存在
HBaseAdmin admin=new HBaseAdmin\(conf\);
if\(!admin.tableExists\(Bytes.toBytes\(tableName\)\)\)
{
System.err.println\("the table "+tableName+" is not exist"\);
System.exit\(1\);
}
//创建表连接
HTable table=new HTable\(conf, TableName.valueOf\(tableName\)\);
//准备删除数据
Delete delete=new Delete\(Bytes.toBytes\(rowKey\)\);
if\(family != null && qualifier != null\)
{
delete.deleteColumn\(Bytes.toBytes\(family\), Bytes.toBytes\(qualifier\)\);
}
else if\(family !=null && qualifier == null\)
{
delete.deleteFamily\(Bytes.toBytes\(family\)\);
}
//检查时间戳
if\(timeStampe!=null\)
{
delete.setTimestamp\(Long.parseLong\(timeStampe\)\);
}
//进行数据删除
table.delete\(delete\);
table.close\(\);
} catch \(Exception e\) {
// TODO: handle exception
}
}
在进行删除会。可以通过指定对某一行的某一个列簇、或者某一个列、或者某一个列中具体版本的数据进行删除。
如果在没有任何设定的情况下,则会删除整行数据。如果使用 addFamily 函数,则会删除改行中的指定列簇中的所有数据。
如果使用 deleteColumns 函数,则会删除该行中的指定列中所有的数据。
如果使用 deleteColumn() 函数则会删除改行中指定列的最大本版本的KeyValue数据。
如果 setTimeStamp 则会删除指定版本的数据。
2、多行删除
多行删除的数据实质就是对List表进行循环,然后多次发送删除请求,从而实现多行删除的效果
public void deleteList(String tableName,String[] rows,String[] families,String[] qualifiers)
{
Configuration conf=init\(\);
try {
HBaseAdmin admin=new HBaseAdmin\(conf\);
if\(!admin.tableExists\(tableName\)\)
{
System.out.println\("the table "+tableName+" is not exist"\);
admin.close\(\);
System.exit\(1\);
}
admin.close\(\);
//创建表连接
HTable table=new HTable\(conf, tableName\);
int length=rows.length;
List<Delete> deletes=new ArrayList<>\(\);
for\(int i=0;i<length;i++\)
{
Delete delete=new Delete\(Bytes.toBytes\(rows\[i\]\)\);
delete.deleteColumn\(Bytes.toBytes\(families\[i\]\), Bytes.toBytes\(qualifiers\[i\]\)\);
deletes.add\(delete\);
}
//进行多行删除
table.delete\(deletes\);
//关闭表连接
table.close\(\);
} catch \(Exception e\) {
// TODO: handle exception
e.printStackTrace\(\);
}
}
3、原子性操作
HTable表提供了一个CAS的原子性操作:checkAndDelete()函数,该函数在多个客户端对一行数据进行操作时进行修改。
public void deleteList(String tableName,String[] rows,String[] families,String[] qualifiers)
{
Configuration conf=init\(\);
try {
HBaseAdmin admin=new HBaseAdmin\(conf\);
if\(!admin.tableExists\(tableName\)\)
{
System.out.println\("the table "+tableName+" is not exist"\);
admin.close\(\);
System.exit\(1\);
}
admin.close\(\);
//创建表连接
HTable table=new HTable\(conf, tableName\);
int length=rows.length;
List<Delete> deletes=new ArrayList<>\(\);
for\(int i=0;i<length;i++\)
{
Delete delete=new Delete\(Bytes.toBytes\(rows\[i\]\)\);
delete.deleteColumn\(Bytes.toBytes\(families\[i\]\), Bytes.toBytes\(qualifiers\[i\]\)\);
deletes.add\(delete\);
}
//进行多行删除
table.delete\(deletes\);
//关闭表连接
table.close\(\);
} catch \(Exception e\) {
// TODO: handle exception
e.printStackTrace\(\);
}
}
在进行这里使用到了一个比较器的选项,在checkAndDelete()函数有两个,两者的差别就在于是否含有一个比较器。不含有比较器的函数效果与有比较器并且比较器的标志为CompareOp.EQUAL的效果是相同的。该函数的意思为,当函数中指定的值小于等于指定的值时,则进行删除操作。
三、Delete对象细节
1、setWriteToWAL()
是否经该删除操作写入到WAL日志中。如果写入日志,则会增加其整个删除动作的时候,但是数据操作将被记录,出现系统崩溃时可以进行数据恢复。如果不写入的话,可以降低删除动作时间,但是如果在没有量操作写入到HDFS中前发生系统崩溃,数据将无法进行恢复。
2、setTTL()
设置一行数据的TTL时间,如果该行数据被设置,则当其时间超过TTL时,KeyValue数据会被删除。
疑问:本身该操作为删除操作,是否需要使用到本函数。
四、批量操作
该本应该问单独成为一章,但是删除和并行操作的内容都比较少,所以就放在同一个知识点上。
1、介绍
在上三节我们提到了Put、Delete、Get操作。并且讲解了他们各自的多行操作。初次之外HBase还提供了一套可以一次执行多条不同种类的操作。可以通过该函数一次进行多行的增加(修改)、删除、查询等多种数据。
(1)进行多项查询,并返回相同数量的结果
public void deleteList(String tableName,String[] rows,String[] families,String[] qualifiers)
{
Configuration conf=init\(\);
try {
HBaseAdmin admin=new HBaseAdmin\(conf\);
if\(!admin.tableExists\(tableName\)\)
{
System.out.println\("the table "+tableName+" is not exist"\);
admin.close\(\);
System.exit\(1\);
}
admin.close\(\);
//创建表连接
HTable table=new HTable\(conf, tableName\);
int length=rows.length;
List<Delete> deletes=new ArrayList<>\(\);
for\(int i=0;i<length;i++\)
{
Delete delete=new Delete\(Bytes.toBytes\(rows\[i\]\)\);
delete.deleteColumn\(Bytes.toBytes\(families\[i\]\), Bytes.toBytes\(qualifiers\[i\]\)\);
deletes.add\(delete\);
}
//进行多行删除
table.delete\(deletes\);
//关闭表连接
table.close\(\);
} catch \(Exception e\) {
// TODO: handle exception
e.printStackTrace\(\);
}
}
在初始化一个List列别中,填充的类为Row,当Get、Delete和Put类都是Row的子类,因此可以将其对象填充到List<Row>容器中。
因为只有Get会返回正确的KeyValue对象值,所以Delete和Put返回的数据都是为Null值,因此将着三个结果集进行显示后除了第一个为正常的数据,其他两项都为Null。
(2)进行多项操作,不返回结果
public void batchWithoutResult(String tableName)
{
Configuration conf=init\(\);
try {
HBaseAdmin admin=new HBaseAdmin\(conf\);
if\(!admin.tableExists\(tableName\)\)
{
System.out.println\("the table "+tableName+" is not exist"\);
admin.close\(\);
System.exit\(1\);
}
//创建batch列表
List<Row> batchs=new ArrayList<>\(\);
//创建一个查询Get
Get get=new Get\(Bytes.toBytes\("row-1"\)\);
batchs.add\(get\);
//创建一个插入put
Put put=new Put\(Bytes.toBytes\("row-10"\)\);
put.addColumn\(Bytes.toBytes\("test"\), Bytes.toBytes\("test1"\), Bytes.toBytes\("value10"\)\);
batchs.add\(put\);
//创建一个删除
Delete delete=new Delete\(Bytes.toBytes\("row-12"\)\);
//delete.deleteFamily\(Bytes.toBytes\("test1"\)\);
batchs.add\(delete\);
//创建表连接
HTable table=new HTable\(conf, tableName\);
table.batch\(batchs\);
} catch \(Exception e\) {
// TODO: handle exception
}
}
上述代码中只是将Put、Get和Delete等进行执行,并没有返回相应的结果。
2、知识点
(1)请求过程
HBase是一个分布式数据库,因此一张表的数据可能会分布在不同的节点中。需要注意的是 region是Hbase分布式存储的最小单位,但region不是HBase存储的最小单位。在HBase中,一张表会被根据行键值的范围划分为几个region,然后不同的region将会放在不同的region服务器上,被服务器上的HRegionServer 所管理和维持。因此我们可以推断出,当我们发送一个查找(插入、删除)请求时,首先客户端能根据请求中的行键值去确定该行键值应该存储在哪一个region上,并且该region在哪一个region服务器上(该查询过程主要使用-ROOT-表、和.meta表,详细过程在须后章节讲解),当定位到操作的region服务器的位置以后,客户端(Client)会将该操作发送到region服务器上,然后请求操作可能会被直接执行,也可能会进入任务队列等待。
(2)batch注意点
batch中不要存放对同一行的操作,因为请求过程中讲到,请求会被发送到相应的服务器节点中。如果batch中出现同行的数据,他们会同事被发送到相应服务器节点中。有因为在region服务器上的队列优化问题,其在客户端执行的顺序与在队列中的顺序可能会出现不相同的情况,这种情况下,可能就会导致软件执行的结果与用户预测的结果不相同的情况。
五、总结
在提供了常规的Get、Put、Delete单行与多行操作后,HBase也提供了batch方法,以提供不同通过行的多次不同种类的操作。因为单行操作的客户端操作已经介绍,如果有需要补充的地方求指出。